<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Geohash转换工具</title>
  <link rel="stylesheet" href="css/output.css">
  <link href="css/font-awesome.min.css" rel="stylesheet">
 
   
</head>
<body class="font-inter bg-gray-50 min-h-screen flex flex-col">
  <!-- 顶部导航栏 -->
  <header class="bg-white shadow-sm sticky top-0 z-10">
    <div class="container mx-auto px-4 py-4 flex justify-between items-center">
      <h1 class="text-2xl font-bold text-dark flex items-center">
        <i class="fa fa-map-marker text-primary mr-2"></i>
        Geohash转换工具
      </h1>
  
    </div>
  </header>

  <!-- 主要内容区域 -->
  <main class="flex-grow container mx-auto px-4 py-8">
    <div class="max-w-4xl mx-auto bg-white rounded-xl shadow-lg p-6 md:p-8 transform hover:shadow-xl transition-all duration-300">
      <!-- 介绍部分 -->
      <div class="mb-8 text-center">
        <h2 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-dark mb-3 text-shadow">经纬度与Geohash相互转换</h2>
        <p class="text-gray-600 max-w-2xl mx-auto">
          这是一个高效的经纬度与Geohash转换工具，支持批量转换。输入经纬度坐标可转换为Geohash编码，输入Geohash编码可转换为经纬度坐标。
        </p>
      </div>

      <!-- 转换表单 -->
      <form id="converterForm" class="space-y-6">
        <!-- 输入区域 -->
        <div class="space-y-4">
          <label for="inputText" class="block text-sm font-medium text-gray-700">
            <i class="fa fa-pencil-square-o mr-1"></i>输入内容
          </label>
          <textarea id="inputText" rows="6" class="input-field" placeholder="请输入经纬度(格式: 纬度,经度)或Geohash编码，每行一个"></textarea>
        </div>

        <!-- 精度设置 -->
        <div class="flex flex-col sm:flex-row gap-4 items-start sm:items-center">
          <label for="precision" class="block text-sm font-medium text-gray-700 flex items-center">
            <i class="fa fa-sliders mr-1"></i>Geohash精度
          </label>
          <input type="number" id="precision" min="1" max="12" value="6" 
            class="input-field w-full sm:w-24" placeholder="精度">
          <p class="text-sm text-gray-500 mt-1 sm:mt-0">
            <i class="fa fa-info-circle mr-1"></i>精度越高，Geohash编码越长，位置越精确
          </p>
        </div>

        <!-- 按钮区域 -->
        <div class="flex flex-col sm:flex-row gap-4 justify-center">
          <button type="button" id="latlonToGeohash" class="btn-primary flex items-center justify-center">
            <i class="fa fa-map-marker mr-2"></i>经纬度转Geohash
          </button>
          <button type="button" id="geohashToLatlon" class="btn-secondary flex items-center justify-center">
            <i class="fa fa-key mr-2"></i>Geohash转经纬度
          </button>
        </div>

        <!-- 输出区域 -->
        <div class="space-y-4">
          <label for="outputText" class="block text-sm font-medium text-gray-700">
            <i class="fa fa-file-text-o mr-1"></i>输出结果
          </label>
          <div class="relative">
            <textarea id="outputText" rows="6" class="input-field" placeholder="转换结果将显示在这里..." readonly></textarea>
            <button type="button" id="copyButton" class="absolute top-2 right-2 text-gray-500 hover:text-primary transition-colors duration-300">
              <i class="fa fa-copy"></i>
            </button>
          </div>
        </div>
      </form>

      <!-- 转换信息 -->
      <div id="conversionInfo" class="mt-6 p-4 bg-gray-50 rounded-lg hidden">
        <div class="flex items-start">
          <div class="flex-shrink-0">
            <i class="fa fa-info-circle text-primary"></i>
          </div>
          <div class="ml-3">
            <h3 class="text-sm font-medium text-gray-800">转换信息</h3>
            <div class="mt-2 text-sm text-gray-600">
              <p><span id="processedCount">0</span> 条记录已处理</p>
              <p><span id="successCount">0</span> 条转换成功</p>
              <p><span id="errorCount">0</span> 条转换失败</p>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 使用示例卡片 -->
    <div class="max-w-4xl mx-auto mt-8 bg-white rounded-xl shadow-lg p-6 md:p-8">
      <h3 class="text-xl font-bold text-dark mb-4 flex items-center">
        <i class="fa fa-lightbulb-o text-primary mr-2"></i>使用示例
      </h3>
      <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
        <div class="bg-gray-50 p-4 rounded-lg">
          <h4 class="font-medium text-gray-800 mb-2">经纬度转Geohash</h4>
          <p class="text-sm text-gray-600 mb-2">输入格式: 纬度,经度</p>
          <pre class="text-xs bg-gray-100 p-2 rounded overflow-x-auto">39.9042,116.4074
31.2304,121.4737
22.5431,114.0579</pre>
        </div>
        <div class="bg-gray-50 p-4 rounded-lg">
          <h4 class="font-medium text-gray-800 mb-2">Geohash转经纬度</h4>
          <p class="text-sm text-gray-600 mb-2">输入格式: Geohash编码</p>
          <pre class="text-xs bg-gray-100 p-2 rounded overflow-x-auto">wx4g0s
wtw3sj
wsk52t</pre>
        </div>
      </div>
    </div>
  </main>

  <!-- 页脚 -->
  <footer class="bg-dark text-white py-8 mt-12">
    <div class="container mx-auto px-4">
      <div class="flex flex-col md:flex-row justify-between items-center">
        <div class="mb-4 md:mb-0">
          <h2 class="text-xl font-bold flex items-center">
            <i class="fa fa-map-marker text-primary mr-2"></i>
            Geohash转换工具
          </h2>
          <p class="text-gray-400 mt-2">高效的经纬度与Geohash互转工具</p>
        </div>
        <div class="flex space-x-6">
          <a href="#" class="text-gray-400 hover:text-white transition-colors duration-300">
            <i class="fa fa-github"></i>
          </a>
          <a href="#" class="text-gray-400 hover:text-white transition-colors duration-300">
            <i class="fa fa-twitter"></i>
          </a>
          <a href="#" class="text-gray-400 hover:text-white transition-colors duration-300">
            <i class="fa fa-linkedin"></i>
          </a>
        </div>
      </div>
      <div class="border-t border-gray-700 mt-6 pt-6 text-center text-gray-400 text-sm">
        <p>&copy; 2025 Geohash转换工具 | XiangYang</p>
      </div>
    </div>
  </footer>

  <!-- Geohash转换逻辑 -->
  <script>
    // 等待DOM加载完成
    document.addEventListener('DOMContentLoaded', function() {
      // 获取DOM元素
      const inputText = document.getElementById('inputText');
      const outputText = document.getElementById('outputText');
      const precision = document.getElementById('precision');
      const latlonToGeohashBtn = document.getElementById('latlonToGeohash');
      const geohashToLatlonBtn = document.getElementById('geohashToLatlon');
      const copyButton = document.getElementById('copyButton');
      const conversionInfo = document.getElementById('conversionInfo');
      const processedCount = document.getElementById('processedCount');
      const successCount = document.getElementById('successCount');
      const errorCount = document.getElementById('errorCount');

      // Base32编码字符集
      const base32 = '0123456789bcdefghjkmnpqrstuvwxyz';

      // 经纬度转Geohash
      function encodeGeohash(latitude, longitude, precisionValue) {
        let geohash = '';
        let bits = 0;
        let bitsTotal = 0;
        let hashValue = 0;
        let maxLat = 90, minLat = -90;
        let maxLon = 180, minLon = -180;
        let mid;
        let isEven = true;

        while (geohash.length < precisionValue) {
          if (isEven) {
            // 处理经度
            mid = (maxLon + minLon) / 2;
            if (longitude > mid) {
              hashValue = (hashValue << 1) | 1;
              minLon = mid;
            } else {
              hashValue = (hashValue << 1) | 0;
              maxLon = mid;
            }
          } else {
            // 处理纬度
            mid = (maxLat + minLat) / 2;
            if (latitude > mid) {
              hashValue = (hashValue << 1) | 1;
              minLat = mid;
            } else {
              hashValue = (hashValue << 1) | 0;
              maxLat = mid;
            }
          }

          isEven = !isEven;
          bits++;
          bitsTotal++;

          if (bits === 5) {
            // 5位一组转换为Base32字符
            geohash += base32.charAt(hashValue);
            bits = 0;
            hashValue = 0;
          }
        }

        return geohash;
      }

      // Geohash转经纬度
      function decodeGeohash(geohash) {
        let isEven = true;
        let minLat = -90, maxLat = 90;
        let minLon = -180, maxLon = 180;
        let lat, lon;

        // 处理每个字符
        for (let i = 0; i < geohash.length; i++) {
          const c = geohash[i];
          const value = base32.indexOf(c);

          if (value === -1) {
            throw new Error('无效的Geohash字符: ' + c);
          }

          // 将Base32值转换为5位二进制
          for (let j = 4; j >= 0; j--) {
            const bit = (value >> j) & 1;
            if (isEven) {
              // 处理经度
              const mid = (minLon + maxLon) / 2;
              if (bit === 1) {
                minLon = mid;
              } else {
                maxLon = mid;
              }
            } else {
              // 处理纬度
              const mid = (minLat + maxLat) / 2;
              if (bit === 1) {
                minLat = mid;
              } else {
                maxLat = mid;
              }
            }
            isEven = !isEven;
          }
        }

        // 计算中心点
        lat = (minLat + maxLat) / 2;
        lon = (minLon + maxLon) / 2;

        return { latitude: lat, longitude: lon };
      }

      // 经纬度转Geohash处理
      function processLatLonToGeohash() {
        const inputLines = inputText.value.trim().split('\n');
        const outputLines = [];
        let success = 0;
        let errors = 0;

        inputLines.forEach(line => {
          if (!line.trim()) return;

          try {
            // 分割经纬度
            const parts = line.split(',').map(part => part.trim());
            if (parts.length !== 2) {
              throw new Error('格式应为: 纬度,经度');
            }

            const lat = parseFloat(parts[0]);
            const lon = parseFloat(parts[1]);

            // 验证经纬度范围
            if (isNaN(lat) || isNaN(lon) || lat < -90 || lat > 90 || lon < -180 || lon > 180) {
              throw new Error('经纬度超出范围');
            }

            // 转换为Geohash
            const geohash = encodeGeohash(lat, lon, parseInt(precision.value, 10));
            outputLines.push(geohash);
            success++;
          } catch (error) {
            outputLines.push(`错误: ${line} - ${error.message}`);
            errors++;
          }
        });

        // 更新输出
        outputText.value = outputLines.join('\n');
        updateConversionInfo(inputLines.length, success, errors);
      }

      // Geohash转经纬度处理
      function processGeohashToLatLon() {
        const inputLines = inputText.value.trim().split('\n');
        const outputLines = [];
        let success = 0;
        let errors = 0;

        inputLines.forEach(line => {
          if (!line.trim()) return;

          try {
            // 解码Geohash
            const geohash = line.trim();
            const { latitude, longitude } = decodeGeohash(geohash);
            
            // 保留适当的小数位数
            const latStr = latitude.toFixed(6);
            const lonStr = longitude.toFixed(6);
            
            outputLines.push(`${latStr},${lonStr}`);
            success++;
          } catch (error) {
            outputLines.push(`错误: ${line} - ${error.message}`);
            errors++;
          }
        });

        // 更新输出
        outputText.value = outputLines.join('\n');
        updateConversionInfo(inputLines.length, success, errors);
      }

      // 更新转换信息
      function updateConversionInfo(total, success, errors) {
        processedCount.textContent = total;
        successCount.textContent = success;
        errorCount.textContent = errors;
        conversionInfo.classList.remove('hidden');
        
        // 添加动画效果
        conversionInfo.classList.add('animate-fade-in');
        setTimeout(() => {
          conversionInfo.classList.remove('animate-fade-in');
        }, 500);
      }

      // 复制结果到剪贴板
      function copyToClipboard() {
        outputText.select();
        document.execCommand('copy');
        
        // 显示复制成功提示
        const originalText = copyButton.innerHTML;
        copyButton.innerHTML = '<i class="fa fa-check"></i>';
        copyButton.classList.add('text-green-500');
        
        setTimeout(() => {
          copyButton.innerHTML = originalText;
          copyButton.classList.remove('text-green-500');
        }, 2000);
      }

      // 添加事件监听器
      latlonToGeohashBtn.addEventListener('click', processLatLonToGeohash);
      geohashToLatlonBtn.addEventListener('click', processGeohashToLatLon);
      copyButton.addEventListener('click', copyToClipboard);

      // 添加表单提交事件
      document.getElementById('converterForm').addEventListener('submit', function(e) {
        e.preventDefault();
      });

      // 添加输入框动画效果
      const textareas = document.querySelectorAll('textarea');
      textareas.forEach(textarea => {
        textarea.addEventListener('focus', function() {
          this.classList.add('shadow-md');
        });
        textarea.addEventListener('blur', function() {
          this.classList.remove('shadow-md');
        });
      });

      // 添加按钮悬停效果
      const buttons = document.querySelectorAll('button');
      buttons.forEach(button => {
        button.addEventListener('mouseenter', function() {
          this.classList.add('scale-105');
        });
        button.addEventListener('mouseleave', function() {
          this.classList.remove('scale-105');
        });
      });
    });
  </script>
</body>
</html>
    